#ifndef SEMANTICNODEMODEL_H_
#define SEMANTICNODEMODEL_H_

#include "SemanticNode.h"
#include "SemanticNodeField.h"
#include "SemanticNodeProperty.h"
#include "SemanticNodeMethod.h"
#include "SemanticNodeEnum.h"
#include "SemanticNodeBlockGenerate.h"
#include "SemanticNodeBlockTerminate.h"
#include "SemanticNodeBlockAdvance.h"
#include "SemanticNodeBlockEnter.h"
#include "SemanticNodeBlockLeave.h"
#include "SemanticNodeBlockSeize.h"
#include "SemanticNodeBlockRelease.h"
#include "SemanticNodeBlockInqueue.h"
#include "SemanticNodeBlockOutqueue.h"
#include "SemanticNodeBlockArrive.h"
#include "SemanticNodeBlockDepart.h"
#include "SemanticNodeBlockModelInstance.h"
#include "SemanticNodeBlockGoto.h"
#include "SemanticNodeBlockIf.h"
#include "SemanticNodeBlockWait.h"
#include "SemanticNodeBlockJoinGroup.h"
#include "SemanticNodeBlockLeaveGroup.h"
#include "SemanticNodeBlockCreate.h"
#include "SemanticNodeBlockSplit.h"
#include "SemanticNodeBlockGather.h"
#include "SemanticNodeBlockExecute.h"
#include "UsingDirectives.h"
#include "../syntax_tree.h"
#include "../main_container.h"

#include <string>
#include <sstream>
#include <map>
#include <vector>

extern MainContainer *compilerData;

class SemanticNodeModel : public SemanticNode {
private:
	/** Odredjuje je li model privatan (true) ili public (false). */
	bool priv;

	/** Ime modela. */
	std::string name;
	/** Using direktive. */
	UsingDirectives *usingDirectives;

	/** Parametri. */
	std::vector<SemanticNodeField *> parameters;

	/** Labele. */
	std::vector<std::string> inLabels;
	std::vector<std::string> outLabels;

	/** Blokovi: key -> labela, value -> blok. */
	std::vector<SemanticNode *> blocks;

	/** Define body naredbe. */
	std::vector<SemanticNodeField *> fields;
	std::vector<SemanticNodeProperty *> properties;
	std::vector<SemanticNodeMethod *> methods;
	std::vector<SemanticNodeEnum *> enums;

	/** GPSS blokovi. */
	std::vector<SemanticNodeBlockGenerate *> generators;
	std::vector<SemanticNodeBlockTerminate *> terminators;
	std::vector<SemanticNodeBlockAdvance *> advancers;
	std::vector<SemanticNodeBlockEnter *> entrants;
	std::vector<SemanticNodeBlockLeave *> leavers;
	std::vector<SemanticNodeBlockSeize *> seizers;
	std::vector<SemanticNodeBlockRelease *> releasers;
	std::vector<SemanticNodeBlockInqueue *> inqueuers;
	std::vector<SemanticNodeBlockOutqueue *> outqueuers;
	std::vector<SemanticNodeBlockArrive *> arrivals;
	std::vector<SemanticNodeBlockDepart *> departures;
	std::vector<SemanticNodeBlockModelInstance *> modelInstances;
	std::vector<SemanticNodeBlockGoto *> gotos;
	std::vector<SemanticNodeBlockIf *> ifs;
	std::vector<SemanticNodeBlockWait *> waiters;
	std::vector<SemanticNodeBlockJoinGroup *> groupJoiners;
	std::vector<SemanticNodeBlockLeaveGroup *> groupLeavers;
	std::vector<SemanticNodeBlockCreate *> creators;
	std::vector<SemanticNodeBlockSplit *> splitters;
	std::vector<SemanticNodeBlockGather *> gatherers;
	std::vector<SemanticNodeBlockExecute *> executors;

	/** Poredak GPSS blokova. */
	std::vector<SemanticNode *> blockOrder;

	std::vector<std::string> flattenLabelList(const SyntaxTreeNode *labelListNode);

	friend std::string flattenNamePeriodAdd(const SyntaxTreeNode &nameNode);

public:
	/**
	 * Stvara novi SemanticNodeModel na temelju sintaksnog cvora i roditelja ovog semantickog cvora.
		*
		* @param syntaxNode Sintaksni cvor iz kojeg se stvara semanticki cvor.
		* @param parent Roditelj ovog semantickog cvora - ne moze biti NULL!
		*/
	SemanticNodeModel(const SyntaxTreeNode *syntaxNode, SemanticNode *parent);
	//~SemanticNodeModel();

	void addFields(std::vector<SemanticNodeField *> fieldNodes);
	void addField(SemanticNodeField *fieldNode);
	void addProperty(SemanticNodeProperty *propertyNode);
	void addMethod(SemanticNodeMethod *methodNode);
	void addEnum(SemanticNodeEnum *enumNode);
	void addParameters(std::vector<SemanticNodeField *> params);
	void addBlockTerminate(SemanticNodeBlockTerminate *terminator);
	void addBlockGenerate(SemanticNodeBlockGenerate *generator);
	void addBlockAdvance(SemanticNodeBlockAdvance *advancer);
	void addBlockEnter(SemanticNodeBlockEnter *entrant);
	void addBlockLeave(SemanticNodeBlockLeave *leaver);
	void addBlockSeize(SemanticNodeBlockSeize *seizer);
	void addBlockRelease(SemanticNodeBlockRelease *releaser);
	void addBlockInqueue(SemanticNodeBlockInqueue *inqueuer);
	void addBlockOutqueue(SemanticNodeBlockOutqueue *outqueuer);
	void addBlockArrive(SemanticNodeBlockArrive *arrivee);
	void addBlockDepart(SemanticNodeBlockDepart *departure);
	void addBlockModelInstance(SemanticNodeBlockModelInstance *modelInstance);
	void addBlockGoto(SemanticNodeBlockGoto *gotoer);
	void addBlockIf(SemanticNodeBlockIf *ifer);
	void addBlockWait(SemanticNodeBlockWait *waiter);
	void addBlockJoinGroup(SemanticNodeBlockJoinGroup *groupJoiner);
	void addBlockLeaveGroup(SemanticNodeBlockLeaveGroup *groupLeaver);
	void addBlockCreate(SemanticNodeBlockCreate *creator);
	void addBlockSplit(SemanticNodeBlockSplit *splitter);
	void addBlockGather(SemanticNodeBlockGather *gatherer);
	void addBlockExecute(SemanticNodeBlockExecute *executor);

	std::string getName();

	bool isPublic() const;
	bool isPrivate() const;

	virtual std::string toDebugString(int tab);
};

#endif /* SEMANTICNODEMODEL_H_ */
